package core

import (
	"fmt"
	"sort"
)

// 定义一些AOI边界值
const (
	AOI_MIN_X int = 85
	AOI_MAX_X int = 410
	AOI_CNT_X int = 10
	AOI_MIN_Y int = 75
	AOI_MAX_Y int = 400
	AOI_CNT_Y int = 20
)

// AOI区域管理模块
type AOIManager struct {
	MinX  int           // 区域左边界坐标
	MaxX  int           // 区域右边界坐标
	CntX  int           // X轴格子数量
	MinY  int           // 区域上边界坐标
	MaxY  int           // 区域下边界坐标
	CntY  int           // Y轴格子数量
	Grids map[int]*Grid // 存在格子集合
}

// 初始化AOI区域管理模块
func NewAOIManager(minX, maxX, cntX, minY, maxY, cntY int) *AOIManager {
	aoi := &AOIManager{
		MinX:  minX,
		MaxX:  maxX,
		CntX:  cntX,
		MinY:  minY,
		MaxY:  maxY,
		CntY:  cntY,
		Grids: make(map[int]*Grid),
	}
	// 给AOI区域内的所有格子进行初始化
	for y := 0; y < cntY; y++ {
		for x := 0; x < cntX; x++ {
			// 格子编号
			gid := y*cntX + x
			// 格子坐标
			gMinX := aoi.MinX + x*aoi.GridWidth()
			gMaxX := aoi.MinX + (x+1)*aoi.GridWidth()
			gMinY := aoi.MinY + y*aoi.GridHeight()
			gMaxY := aoi.MinY + (y+1)*aoi.GridHeight()
			// 初始化格子
			aoi.Grids[gid] = NewGrid(gid, gMinX, gMaxX, gMinY, gMaxY)
		}
	}
	return aoi
}

// ----base----

// 返回每个格子X轴长度
func (aoi *AOIManager) GridWidth() int {
	return (aoi.MaxX - aoi.MinX) / aoi.CntX
}

// 返回每个格子Y轴长度
func (aoi *AOIManager) GridHeight() int {
	return (aoi.MaxY - aoi.MinY) / aoi.CntY
}

// 返回当前GID, 通过坐标
func (aoi *AOIManager) GetGIDByPos(x, y float32) (gid int) {
	idx := (int(x) - aoi.MinX) / aoi.GridWidth()
	idy := (int(y) - aoi.MinY) / aoi.GridHeight()
	return idy*aoi.CntX + idx
}

// 返回格子切片, 通过GIDs
func (aoi *AOIManager) GetGridsByGIDs(gids []int) (grids []*Grid) {
	// 初始化格子切片
	grids = make([]*Grid, 0, len(gids))
	// 遍历id切片, 返回格子切片
	for _, gid := range gids {
		grids = append(grids, aoi.Grids[gid])
	}
	return grids
}

// 返回九宫格的GIDs切片, 通过GID
func (aoi *AOIManager) GetSurroundGIDsByGID(gid int) (gids []int) {
	// 判断gID是否存在当前AOI中
	if _, ok := aoi.Grids[gid]; !ok {
		return nil
	}
	// 初始化id切片
	gids = make([]int, 0, 9)
	// x轴方向gID, 存放在id切片中
	gids = append(gids, gid)
	idx := gid % aoi.CntX
	if idx > 0 {
		gids = append(gids, gid-1)
	}
	if idx < aoi.CntX-1 {
		gids = append(gids, gid+1)
	}
	// y轴方向gID, 存放在id切片中
	for _, v := range gids {
		if _, ok := aoi.Grids[v-aoi.CntX]; ok {
			gids = append(gids, v-aoi.CntX)
		}
		if _, ok := aoi.Grids[v+aoi.CntX]; ok {
			gids = append(gids, v+aoi.CntX)
		}
	}
	sort.Ints(gids)
	return gids
}

// 返回PlayIDs切片, 通过GID
func (aoi *AOIManager) GetPlayerIDsByGid(gid int) (playIDs []int) {
	playIDs = make([]int, 0, len(aoi.Grids[gid].PlayerIDs))
	playIDs = append(playIDs, aoi.Grids[gid].GetPlayerIDs()...)
	return playIDs
}

// 返回PlayIDs切片, 通过GIDs切片
func (aoi *AOIManager) GetPlayerIDsByGIDs(gids []int) (playIDs []int) {
	playIDs = make([]int, 0)
	for _, gid := range gids {
		playIDs = append(playIDs, aoi.GetPlayerIDsByGid(gid)...)
	}
	return playIDs
}

// ----base----

// ----playerID----

// 在指定格子中, 添加玩家
func (aoi *AOIManager) AddPlayerIDToGrid(playerID, gid int) {
	aoi.Grids[gid].Add(playerID)
}

// 在指定格子中, 删除玩家
func (aoi *AOIManager) RemovePlayerIDToGrid(playerID, gid int) {
	aoi.Grids[gid].Remove(playerID)
}

// ----playerID----

// ----Surround----

// 返回九宫格的切片, 通过GID
func (aoi *AOIManager) GetSurroundGridsByGID(gid int) (grids []*Grid) {
	// 返回九宫格的GIDs切片, 通过GID
	gids := aoi.GetSurroundGIDsByGID(gid)
	// 返回格子切片, 通过GIDs
	grids = aoi.GetGridsByGIDs(gids)
	return grids
}

// 返回九宫格内PlayIDs的切片, 通过GID
func (aoi *AOIManager) GetSurroundPlayerIDsByGID(gid int) (playIDs []int) {
	// 返回九宫格的Gids切片, 通过GID
	grids := aoi.GetSurroundGIDsByGID(gid)
	// 返回PlayIDs切片, 通过GIDs切片
	playIDs = aoi.GetPlayerIDsByGIDs(grids)
	return playIDs
}

// ----Surround----

//--------------------------------------------
// 调试-打印AOI区域信息
func (aoi *AOIManager) String() string {
	// AOI基本信息
	s := fmt.Sprintf("[AOI]\nMinX: %d, MaxX: %d, CntX: %d\nMinY: %d, MaxY: %d, CntY: %d\n",
		aoi.MinX, aoi.MaxX, aoi.CntX, aoi.MinY, aoi.MaxY, aoi.CntY)
	// AOI内所有Grid格子信息
	// 按照ID排序
	gids := make([]int, 0, len(aoi.Grids))
	for gid := range aoi.Grids {
		gids = append(gids, gid)
	}
	sort.Ints(gids)
	// 排序后添加到打印信息
	for _, k := range gids {
		s += aoi.Grids[k].String()
	}
	return s
}
